/**
 * Copyright 2020 OPSLI 快速开发平台 https://www.opsli.com
 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package org.opsli.modulars.business.projectRecord.web;

import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.convert.Convert;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.ss.usermodel.BorderStyle;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.usermodel.VerticalAlignment;
import org.apache.poi.ss.util.CellRangeAddress;
import org.opsli.api.web.business.projectRecord.ProjectRecordRestApi;
import org.opsli.api.wrapper.business.emergency.EmergencyReportModel;
import org.opsli.api.wrapper.projectRecord.ProjectRecordModel;
import org.opsli.api.wrapper.system.user.UserModel;
import org.opsli.common.annotation.RequiresPermissionsCus;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.opsli.api.base.result.ResultVo;
import org.opsli.common.annotation.ApiRestController;
import org.opsli.common.annotation.EnableLog;
import org.opsli.core.base.controller.BaseRestController;
import org.opsli.core.persistence.Page;
import org.opsli.core.persistence.querybuilder.QueryBuilder;
import org.opsli.core.persistence.querybuilder.WebQueryBuilder;
import org.opsli.core.utils.UserUtil;
import org.opsli.modulars.business.app.web.ZkUtils;
import org.opsli.modulars.business.emergency.service.IEmergencyReportService;
import org.opsli.modulars.business.projectRecord.entity.ProjectRecord;
import org.opsli.modulars.business.projectRecord.service.IProjectRecordService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 工程项目 Controller
 *
 * @author Ljc
 * @date 2022-08-26 10:36:26
 */
@Api(tags = ProjectRecordRestApi.TITLE)
@Slf4j
@ApiRestController("/projectRecord")
public class ProjectRecordRestController extends BaseRestController<ProjectRecord, ProjectRecordModel, IProjectRecordService>
    implements ProjectRecordRestApi {

    @Autowired
    private IEmergencyReportService iEmergencyReportService;

    @Autowired
    private IProjectRecordService iProjectRecordService;

    String projectName="";

    /**
    * 工程项目 查一条
    * @param model 模型
    * @return ResultVo
    */
    @ApiOperation(value = "获得单条工程项目", notes = "获得单条工程项目 - ID")
    @Override
    public ResultVo<ProjectRecordModel> get(ProjectRecordModel model) {
        // 如果系统内部调用 则直接查数据库
        if(model != null && model.getIzApi() != null && model.getIzApi()){
            model = IService.get(model);
        }
        return ResultVo.success(model);
    }

    /**
    * 工程项目 查询分页
    * @param pageNo 当前页
    * @param pageSize 每页条数
    * @param request request
    * @return ResultVo
    */
    @ApiOperation(value = "获得分页数据", notes = "获得分页数据 - 查询构造器")
    @Override
    public ResultVo<?> findPage(Integer pageNo, Integer pageSize, HttpServletRequest request) {
        Map<String,String[]> queryMap = new LinkedHashMap(request.getParameterMap());
        queryMap.put("devid_EQ",new String[]{UserUtil.getSysUser().getCompanyId()});

        Object o3=queryMap.get("projectName_LIKE");
        if(o3!=null){
            String[] arr=(String[])o3;
            projectName=arr[0];
        }

        QueryBuilder<ProjectRecord> queryBuilder = new WebQueryBuilder<>(entityClazz, queryMap);
        Page<ProjectRecord, ProjectRecordModel> page = new Page<>(pageNo, pageSize);
        page.setQueryWrapper(queryBuilder.build());
        page = IService.findPage(page);
        //获取当前页数据
        List<ProjectRecordModel> list = page.getList();

        //当前页项目的项目id
        List<String> idStr = new ArrayList<>();
        if (list.size() > 0 && !list.isEmpty() && list != null) {
            for (ProjectRecordModel model : list) {
                idStr.add(model.getId());
            }
        }

        //项目id下的所有上报记录-计算每个项目下已上报的安装设备数量
        List<EmergencyReportModel> reportList = iProjectRecordService.findReportList(idStr);
        Map<String,Integer> reportMap = new HashMap<>();
        if (idStr.size() > 0 && !idStr.isEmpty() && idStr != null) {
            if (reportList != null && reportList.size() > 0 && !reportList.isEmpty()) {
                for (int i = 0; i < idStr.size(); i++) {
                    int count = 0;
                    String id = idStr.get(i);
                    for (int j = 0; j < reportList.size(); j++){
                        String projectId = reportList.get(j).getProjectId();
                        if (id.equals(projectId)){
                            int num = reportList.get(j).getInstalledNumber();
                            count += num;
                        }
                    }
                    reportMap.put(id,count);
                }
            }
        }

        //计算项目进度
        if (list != null && list.size() > 0 && !list.isEmpty()) {
            for (ProjectRecordModel model : list) {
                int deviceNumber = model.getDeviceNumber();
                int installedNumber = reportMap.get(model.getId());
                if (installedNumber == 0 || deviceNumber == 0) {
                    model.setProjectProgress(0);
                }else{
                    double con2 = division(installedNumber*0.1,deviceNumber*0.1,2)*100;
                    int con1 = (int) Math.round(con2);
                    model.setProjectProgress(con1);
                }
            }
        }

        return ResultVo.success(page.getPageData());
    }

    /**
     * 导出Excel报表
     * @param request
     * @param response
     */
    @RequestMapping(value = "/projectExcel", method = RequestMethod.GET)
    public void getProjectExcel(HttpServletRequest request, HttpServletResponse response) {
        String devid = UserUtil.getSysUser().getCompanyId();
        List<ProjectRecordModel> l = iProjectRecordService.getProjectExcel(devid,projectName);

        //当前页项目的项目id
        List<String> idStr = new ArrayList<>();
        if (l.size() > 0 && !l.isEmpty() && l != null) {
            for (ProjectRecordModel model : l) {
                idStr.add(model.getId());
            }
        }
        //项目id下的所有上报记录-计算每个项目下已上报的安装设备数量
        List<EmergencyReportModel> reportList = iProjectRecordService.findReportList(idStr);
        Map<String,Integer> reportMap = new HashMap<>();
        if (idStr.size() > 0 && !idStr.isEmpty() && idStr != null) {
            if (reportList != null && reportList.size() > 0 && !reportList.isEmpty()) {
                for (int i = 0; i < idStr.size(); i++) {
                    int count = 0;
                    String id = idStr.get(i);
                    for (int j = 0; j < reportList.size(); j++){
                        String projectId = reportList.get(j).getProjectId();
                        if (id.equals(projectId)){
                            int num = reportList.get(j).getInstalledNumber();
                            count += num;
                        }
                    }
                    reportMap.put(id,count);
                }
            }
        }
        //计算项目进度
        if (l != null && l.size() > 0 && !l.isEmpty()) {
            for (ProjectRecordModel model : l) {
                int deviceNumber = model.getDeviceNumber();
                int installedNumber = reportMap.get(model.getId());
                if (installedNumber == 0 || deviceNumber == 0) {
                    model.setProjectProgress(0);
                }else{
                    double con2 = division(installedNumber*0.1,deviceNumber*0.1,2)*100;
                    int con1 = (int) Math.round(con2);
                    model.setProjectProgress(con1);
                }
            }
        }

        ProjectRecordRestController pr = new ProjectRecordRestController();
        String titleName = "工程项目报表";
        //输出文件流
        OutputStream output = null;
        try {
            output = response.getOutputStream();
            response.reset();
            response.setHeader("Content-Disposition",
                    "attchement;filename=" + new String(("工程项目报表" + ZkUtils.getDateStr().substring(0, 10) + ".xls").getBytes("gb2312"), "ISO8859-1"));
            response.setContentType("application/msexcel");
        } catch (IOException e) {
            e.printStackTrace();
        }
        HSSFWorkbook book = null;
        try {
            book = new HSSFWorkbook(pr.getExcelFiles(l, titleName));
        } catch (IOException ioException) {
            ioException.printStackTrace();
        }
        try {
            book.write(output);
        } catch (IOException ioException) {
            ioException.printStackTrace();
        }
        try {
            output.flush();
        } catch (IOException ioException) {
            ioException.printStackTrace();
        }
        try {
            output.close();
        } catch (IOException ioException) {
            ioException.printStackTrace();
        }
    }

    //导出Excel样式
    private HSSFWorkbook workbook;
    private HSSFSheet sheet;

    public InputStream getExcelFiles(List<ProjectRecordModel> l, String titleName) throws IOException {
        //获取当前系统时间
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");//设置日期格式
        String sheetName = df.format(new Date());
        //创建sheet
        workbook = new HSSFWorkbook();
        sheet = workbook.createSheet(sheetName);
        //字体样式
        HSSFFont font = workbook.createFont();
        font.setFontName("宋体");
        font.setFontHeightInPoints((short) 16);// 字体大小
        //字体加粗样式
        HSSFFont font0 = workbook.createFont();
        font0.setFontName("宋体");
        font0.setFontHeightInPoints((short) 20);
        font0.setBold(true);
        //通用字体样式
        HSSFCellStyle cs0 = workbook.createCellStyle();//创建第一行样式
        cs0.setAlignment(HorizontalAlignment.CENTER);// 左右居中2 居右3 默认居左
        cs0.setFont(font);
        cs0.setVerticalAlignment(VerticalAlignment.CENTER);// 上下居中1
        cs0.setBorderBottom(BorderStyle.THIN);
        cs0.setBorderLeft(BorderStyle.THIN);
        cs0.setBorderRight(BorderStyle.THIN);
        cs0.setBorderTop(BorderStyle.THIN);

        //字体加粗样式
        HSSFCellStyle css0 = workbook.createCellStyle();//创建第一行样式
        css0.setAlignment(HorizontalAlignment.CENTER);
        css0.setFont(font0);

        HSSFRow h0 = sheet.createRow(0);//创建一行
        HSSFCell c0 = h0.createCell(0);//在第一行创建一个cell
        c0.setCellValue(titleName);//设置头部标题，巡检日报表或巡检月报表
        c0.setCellStyle(css0);
        CellRangeAddress cra0 = new CellRangeAddress(0, 0, 0, 4);//合并行
        sheet.addMergedRegion(cra0);
        setBorderStyle(1, cra0, sheet, workbook);
        //小区名称
        //exRow1
        HSSFRow h1 = sheet.createRow(1);//获取第二行
        HSSFCell c1 = h1.createCell(0);//巡检员
        c1.setCellValue("项目名称");
        c1.setCellStyle(cs0);
        HSSFCell c2 = h1.createCell(1);//巡线次数
        c2.setCellValue("项目类别");
        c2.setCellStyle(cs0);
        HSSFCell c3 = h1.createCell(2);//总共巡线时间
        c3.setCellValue("设备数量");
        c3.setCellStyle(cs0);
        HSSFCell c4 = h1.createCell(3);//巡线距离
        c4.setCellValue("项目进度");
        c4.setCellStyle(cs0);
        HSSFCell c5 = h1.createCell(4);//巡点次数
        c5.setCellValue("第一责任人");
        c5.setCellStyle(cs0);
        for (int s = 0; s <= 8; s++) {
            sheet.setColumnWidth(s, 5000);
        }
        for (int h = 0; h < l.size(); h++) {
            ProjectRecordModel di = l.get(h);
            int n = 2 + h;
            HSSFRow h4 = sheet.createRow(n);
            HSSFCell c01 = h4.createCell(0);
            c01.setCellValue(di.getProjectName());
            c01.setCellStyle(cs0);
            HSSFCell c02 = h4.createCell(1);
            if (di.getProjectType() != null ){
                if (di.getProjectType().equals("1")){
                    c02.setCellValue("场站");
                }else if (di.getProjectType().equals("2")){
                    c02.setCellValue("远传");
                }else if (di.getProjectType().equals("3")){
                    c02.setCellValue("场站+远传");
                }else{
                    c02.setCellValue("");
                }
            }else{
                c02.setCellValue(di.getProjectType());
            }

            c02.setCellStyle(cs0);
            HSSFCell c03 = h4.createCell(2);
            c03.setCellValue(di.getDeviceNumber());
            c03.setCellStyle(cs0);
            HSSFCell c04 = h4.createCell(3);
            c04.setCellValue(String.valueOf(di.getProjectProgress())+"%");
            c04.setCellStyle(cs0);
            HSSFCell c05 = h4.createCell(4);
            c05.setCellValue(di.getPersonLiable());
            c05.setCellStyle(cs0);
        }
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        workbook.write(baos);
        byte[] ba = baos.toByteArray();
        ByteArrayInputStream bais = new ByteArrayInputStream(ba);
        return bais;
    }

    //加边框
    private static void setBorderStyle(int border, CellRangeAddress region, HSSFSheet sheet, HSSFWorkbook wb) {
        HSSFCellStyle cs = wb.createCellStyle(); // 样式对象
        HSSFFont font = wb.createFont();
        font.setFontName("宋体");
        font.setFontHeightInPoints((short) 16);
        font.setBold(true);
        cs.setFont(font);
        cs.setAlignment(HorizontalAlignment.CENTER);
        cs.setVerticalAlignment(VerticalAlignment.CENTER);
        cs.setBorderBottom(BorderStyle.valueOf((short) border));
        cs.setBorderTop(BorderStyle.valueOf((short) border));
        cs.setBorderLeft(BorderStyle.valueOf((short) border));
        cs.setBorderRight(BorderStyle.valueOf((short) border));
        setRegionStyle(cs, region, sheet);
    }

    private static void setRegionStyle(HSSFCellStyle cs, CellRangeAddress region, HSSFSheet sheet) {
        for (int i = region.getFirstRow(); i <= region.getLastRow(); i++) {
            HSSFRow row = sheet.getRow(i);
            if (row == null) {
                row = sheet.createRow(i);
            }
            for (int j = region.getFirstColumn(); j <= region.getLastColumn(); j++) {
                HSSFCell cell = row.getCell(j);
                if (cell == null) {
                    cell = row.createCell(j);
                    cell.setCellValue("");
                }
                cell.setCellStyle(cs);
            }
        }
    }

    /**
     * 除法
     * @param v1
     * @param v2
     * @param scale
     * @return
     */
    public static double division(double v1, double v2, int scale) {
        if (scale < 0) {
            throw new IllegalArgumentException(
                    "The scale must be a positive integer or zero");
        }
        BigDecimal b1 = new BigDecimal(Double.toString(v1));
        BigDecimal b2 = new BigDecimal(Double.toString(v2));
        return b1.divide(b2, scale, BigDecimal.ROUND_HALF_UP).doubleValue();
    }

    /**
    * 工程项目 新增
    * @param model 模型
    * @return ResultVo
    */
    @ApiOperation(value = "新增工程项目数据", notes = "新增工程项目数据")
    @RequiresPermissions("projectrecord_projectrecord_insert")
    @EnableLog
    @Override
    public ResultVo<?> insert(ProjectRecordModel model) {
        UserModel userModel= UserUtil.getSysUser();
        model.setDevid(userModel.getCompanyId());
        // 调用新增方法
        IService.insert(model);
        return ResultVo.success("新增工程项目成功");
    }

    /**
    * 工程项目 修改
    * @param model 模型
    * @return ResultVo
    */
    @ApiOperation(value = "修改工程项目数据", notes = "修改工程项目数据")
    @RequiresPermissions("projectrecord_projectrecord_update")
    @EnableLog
    @Override
    public ResultVo<?> update(ProjectRecordModel model) {
        UserModel userModel= UserUtil.getSysUser();
        model.setDevid(userModel.getCompanyId());
        // 调用修改方法
        IService.update(model);
        return ResultVo.success("修改工程项目成功");
    }


    /**
    * 工程项目 删除
    * @param id ID
    * @return ResultVo
    */
    @ApiOperation(value = "删除工程项目数据", notes = "删除工程项目数据")
    @RequiresPermissions("projectrecord_projectrecord_update")
    @EnableLog
    @Override
    public ResultVo<?> del(String id){
        IService.delete(id);
        return ResultVo.success("删除工程项目成功");
    }

    @Override
    public ResultVo<?> delById(String id) {

        List<EmergencyReportModel> list = iEmergencyReportService.findListByProjectId(id);

        if(list.size()==0){
            return ResultVo.success("0");
        }else {
            return ResultVo.success("1");
        }
    }

    /**
    * 工程项目 批量删除
    * @param ids ID 数组
    * @return ResultVo
    */
    @ApiOperation(value = "批量删除工程项目数据", notes = "批量删除工程项目数据")
    @RequiresPermissions("projectrecord_projectrecord_update")
    @EnableLog
    @Override
    public ResultVo<?> delAll(String ids){
        String[] idArray = Convert.toStrArray(ids);
        IService.deleteAll(idArray);
        return ResultVo.success("批量删除工程项目成功");
    }


    /**
    * 工程项目 Excel 导出
    * 注：这里 RequiresPermissionsCus 引入的是 自定义鉴权注解
    *
    * 导出时，Token认证和方法权限认证 全部都由自定义完成
    * 因为在 导出不成功时，需要推送错误信息，
    * 前端直接走下载流，当失败时无法获得失败信息，即使前后端换一种方式后端推送二进制文件前端再次解析也是最少2倍的耗时
    * ，且如果数据量过大，前端进行渲染时直接会把浏览器卡死
    * 而直接开启socket接口推送显然是太过浪费资源了，所以目前采用Java最原始的手段
    * response 推送 javascript代码 alert 提示报错信息
    *
    * @param request request
    * @param response response
    */
    @ApiOperation(value = "导出Excel", notes = "导出Excel")
    @RequiresPermissionsCus("projectrecord_projectrecord_export")
    @EnableLog
    @Override
    public void exportExcel(HttpServletRequest request, HttpServletResponse response) {
        // 当前方法
        Method method = ReflectUtil.getMethodByName(this.getClass(), "exportExcel");
        QueryBuilder<ProjectRecord> queryBuilder = new WebQueryBuilder<>(entityClazz, request.getParameterMap());
        super.excelExport(ProjectRecordRestApi.SUB_TITLE, queryBuilder.build(), response, method);
    }

    /**
    * 工程项目 Excel 导入
    * 注：这里 RequiresPermissions 引入的是 Shiro原生鉴权注解
    * @param request 文件流 request
    * @return ResultVo
    */
    @ApiOperation(value = "导入Excel", notes = "导入Excel")
    @RequiresPermissions("projectrecord_projectrecord_import")
    @EnableLog
    @Override
    public ResultVo<?> importExcel(MultipartHttpServletRequest request) {
        return super.importExcel(request);
    }

    /**
    * 工程项目 Excel 下载导入模版
    * 注：这里 RequiresPermissionsCus 引入的是 自定义鉴权注解
    * @param response response
    */
    @ApiOperation(value = "导出Excel模版", notes = "导出Excel模版")
    @RequiresPermissionsCus("projectrecord_projectrecord_import")
    @Override
    public void importTemplate(HttpServletResponse response) {
        // 当前方法
        Method method = ReflectUtil.getMethodByName(this.getClass(), "importTemplate");
        super.importTemplate(ProjectRecordRestApi.SUB_TITLE, response, method);
    }

}
